package util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This class is responsible for retrieving files i.e. the XML-files,
 * which contains data needed by the program.
 * @author Christian, Michal og Jakob (Hold 1, gruppe 2)
 */
public class FileGetter {
    
    /**
     * Method to get the current working directory, purely a convenience and portability method
     * This method used to get the path of the jar files, but currently does nothing, it is purely a compatability method
     * @param s
     * @return s
     */
    
    public static String getPathToFile(String s)
    {
        return s;
    }
    
    /**
     * Old getPathToFile method to get the path to a file/directory inside a jar file.
     * This method is kept incase it is needed at a later stage, also acts as documentation
     * This method works by converting the path to an URL and then to an URI.
     * It is assumed that the input path given is to a file/directory inside a jar file
     * 
     * @param s
     * @return path to the file
     */
    
    public static String getPathToFileOld(String s)
    {
        s = getPathToDataDirectory(s) + s;
        File f = new File("");

        
        URI uri = null;
        URL url = FileGetter.class.getResource(s);
        
        try{ 
            uri = url.toURI(); 
        }
        catch (Exception e)
        { 
            System.err.println("ERROR: FileGetter cannot read file " + s + " URL: " + url + " current Directory: " + f.getAbsolutePath() + 
                    " alternative: " + System.getProperty("user.dir"));
                    URL url2 = FileGetter.class.getResource("README.TXT");
                    System.out.println("url 2: " + url2);
                          
        }
     
     
     assert uri != null : "ERROR: URI == null";
     
     String pathToFile = uri.getPath();
     return pathToFile;
    }
    /**
     * Gets a list of all the XML files in the given directory
     * 
     * This method uses the File class to get a list of all the files ending with ".xml"
     * in the given directory.
     * 
     * @param s the relative or absolute path to the directory
     * @return ArrayList containing file names as Strings
     */
    
    
    public static ArrayList<String> getXMLFilesInDirectoryAsArrayList(String s)
    {
        //s = getPathToFile(s);
        
        File directory = new File(s);
        File[] files = directory.listFiles();
        assert files.length != 0 : "FileGetter: getXMLFilesInDirectoryAsArrayList: no XML files in directory";
        ArrayList<String> xmlFilesInDirectory = new ArrayList<String>();
        
        for(int i = 0; i < files.length; i++)
        {
            if( files[i].getPath().endsWith(".xml") || files[i].getPath().toLowerCase().endsWith(".xml") )
            {
                assert files[i].exists() : "FileGetter: getXMLFilesInDirectoryAsArrayList: file does not exist ";
                xmlFilesInDirectory.add( files[i].getPath() );
            }

        }
        

        assert xmlFilesInDirectory.size() != 0 : "No XML Files in directory";
        return xmlFilesInDirectory;
    }
    
    /**
     * gets the Path to the Data Directory, compatability method. Does nothing.
     * 
     * @param s 
     * @return s
     */
    
    public static String getPathToDataDirectory(String s)
    {
        return s;
    }
    
    /**
     * Gets a file from an URL as a BufferedInputStream, useful for XML parsing
     * @param s the URL to the file
     * @return the file as a stream
     */
    
    public static BufferedInputStream getFileAsInputStreamFromURL(String s)
    {
        BufferedInputStream input = null;
        URLConnection connectionToServer = null;
        URL url = null;
        
        try
        {
            url = new URL(s);
            connectionToServer = url.openConnection();
            input = new BufferedInputStream(connectionToServer.getInputStream(), 1024);
            
        }
        catch(Exception e)
        {
            
        }
        
        return input;
    }
    
    /**
     * Gets a file as an FileInputStream. Useful for XML parsing
     * @param s the relative or absolute path to the file
     * @return the file as a stream
     */
    
    
    
    public static FileInputStream getFileAsFileInputStream(String s)
    {
        String pathToFile = FileGetter.getPathToFile(s);
        File file = new File(pathToFile);
        assert file.exists() : "FileGetter: getFileAsInputStream: file does not exist";
        FileInputStream returnedInputStream = null;
        try
        {
            returnedInputStream = new FileInputStream(file);
        }
        catch (Exception e) { System.err.println("ERROR: cannot open fileinputstream: " + file.getAbsolutePath()); }
        
        return returnedInputStream;
    }
    
    /**
     * Gets a file as a FileInputStream, only absolute path.
     * Converts a file to a FileInputStream
     * @param s the absolute path to the file
     * @return the file as a stream
     */
    
    public static FileInputStream getFileAsFileInputStreamAbsolutePath(String s)
    {
        File file = new File(s);
        FileInputStream returnedInputStream = null;
        try
        {
            returnedInputStream = new FileInputStream(file);
        }
        catch (Exception e) { System.err.println("ERROR: cannot open fileinputstream"); }
        
        return returnedInputStream;
    }
    
    /**
     * Gets all files and directories in the given directory
     * @param s the relative or absolute path to the directory containing files/directories
     * @return the files and directories as a String arrray
     */
    
    public static String[] getFilesAndDirectories(String s)
    {
        String pathToFile = FileGetter.getPathToFile(s);
        
        File file = new File(pathToFile);
        
        String[] filesAndDirectories = file.list();
        
        return filesAndDirectories;
        
        
    }
    
    /**
     * Gets all the XML files in the update directory.
     * Gets all the files ending with .xml in the update directory, that is the directory containing the
     * XML files that specify the POIs
     * 
     * @return an ArrayList containing the names of the files as strings
     */
    
    
    public static ArrayList<String> getXMLFilesInUpdateDirectory()
    {
        String s = getUpdateDirectory();
        ArrayList<String> files = getXMLFilesInDirectoryAsArrayList(s);
        return files;
    }
    
    /**
     * Gets the path to the update directory.
     * This method gets the relative path to the update directory which contains the XML files that specify the POIS.
     * @return the relative path to the update directory as a String
     */
    
    public static String getUpdateDirectory()
    {
        return "Data" + "/" + "latestupdate";
    }
    
    /**
     * Deletes the specified files in the update directory.
     * This method deletes all the files given in the parameters which reside in the update directory.
     * 
     * NOTE: this method can delete any file but should only be used for XML files
     * @param filesToBeDeleted an ArrayList of the filenames of the files to be deleted
     */
    
    public static void deleteXMLFilesInUpdateDirectory(ArrayList<String> filesToBeDeleted)
    {
        String s = getUpdateDirectory();
        
        for(int i = 0; i < filesToBeDeleted.size(); i++)
        {
            //String currentFilePath = s + "\\" + filesToBeDeleted.get(i);
            String currentFilePath = filesToBeDeleted.get(i);
            File f = new File(currentFilePath);
            assert f.exists() : "FileGetter: deleteXMLFilesInUpdateDirectory: file: " + currentFilePath + " does not exist";
            f.delete(); // delete the file
            System.out.println("deleted file: " + filesToBeDeleted.get(i));
        }
    }
    
    /**
     * Downloads XML files to the update directory and returns a list of the files which could not be downloaded.
     * This method downloads all the given files at the given host, returns a list of the files which could not be downloaded.
     * 
     * NOTE: This method will override/replace any files in the update directory which have the same name as the file downloaded.
     * @param pathToServer the URL to the server where the XML files are
     * @param filesToBeDownloaded the files which should be downloaded
     * @return the files which could not be downloaded
     */
    
    public static ArrayList<String> downloadXMLFilesToUpdateDirectory(String pathToServer, ArrayList<String> filesToBeDownloaded)
    {
        ArrayList<String> filesThatCouldNotBeDownloaded = new ArrayList<String>();
        
        for(int i = 0; i < filesToBeDownloaded.size(); i++)
        {
            String fullPathToFile = pathToServer + "/" + filesToBeDownloaded.get(i);
            if( downloadFileFromUrl(fullPathToFile, (getUpdateDirectory() + System.getProperty("file.separator") + filesToBeDownloaded.get(i) ) ) == true )
            {
                // do nothing
            }
            else // if the file could not be downloaded...
            {
                filesThatCouldNotBeDownloaded.add( filesToBeDownloaded.get(i) );
            }
            
        }
        
        return filesThatCouldNotBeDownloaded;
    }
    
    /**
     * Downloads a file and saves the file at at the given path and as the given filename.
     * @param s the path to the file as an URL
     * @param outputFileNameAndPath the path and filename of the file that should be saved
     * @return true if the file was downloaded successfuly, false if otherwise
     */
   
    
    private static boolean downloadFileFromUrl(String s, String outputFileNameAndPath)
    {
        BufferedInputStream bufferedInput = null;
        URLConnection connectionToServer = null;
        BufferedOutputStream output = null;
        File outputFile = new File(outputFileNameAndPath);
        
        try
        {
            URL urlToXML = new URL(s);
            connectionToServer = urlToXML.openConnection();
            bufferedInput = new BufferedInputStream(connectionToServer.getInputStream(), 1024);
            output = new BufferedOutputStream(new FileOutputStream(outputFile), 1024);
            int dataRead;
            
            while( (dataRead = bufferedInput.read()) != -1)
            {
                output.write(dataRead);
            }
          
        }
        catch(MalformedURLException murle)
        {
            System.err.println("File could not be downloaded");
            return false;
        }
        catch(IOException ioe)
        {
            System.err.println("File could not be downloaded");
            return false;
        }
        
        finally {
                    try {
                            if (bufferedInput != null) 
                                {
                                    bufferedInput.close(); 
                                }
                            if (output != null) 
                                {
                                    output.close(); 
                                }
                            } 
                        catch (IOException ioe) 
                        {
                            
			}
		}
        
        return true;
    }
}
